<?php
require_once($_SERVER['DOCUMENT_ROOT'].'../system/config.php');
require_once($INCLUDE_DIR.'pel/PelJpeg.php');
require_once($INCLUDE_DIR.'cametrics.helper.php');
/**
 * Convert a decimal degree into degrees, minutes, and seconds.
 *
 * @param int the degree in the form 123.456. Must be in the interval
 * [-180, 180].
 *
 * @return array a triple with the degrees, minutes, and seconds. Each
 * value is an array itself, suitable for passing to a
 * PelEntryRational. If the degree is outside the allowed interval,
 * null is returned instead.
 */
function convertDecimalToDMS($degree) {
	if ($degree > 180 || $degree < -180)
		return null;

	$degree = abs($degree);            // make sure number is positive
		     // (no distinction here for N/S
		     // or W/E).

	$seconds = $degree * 3600;         // Total number of seconds.

	$degrees = floor($degree);         // Number of whole degrees.
	$seconds -= $degrees * 3600;       // Subtract the number of seconds
		     // taken by the degrees.

	$minutes = floor($seconds / 60);   // Number of whole minutes.
	$seconds -= $minutes * 60;         // Subtract the number of seconds
		     // taken by the minutes.

	$seconds = round($seconds*100, 0); // Round seconds with a 1/100th
		     // second precision.

	return array(array($degrees, 1), array($minutes, 1), array($seconds, 100));
}

/**
 * Add GPS information to an image basic metadata. Any old Exif data
 * is discarded.
 *
 * @param string the input filename.
 *
 * @param string the output filename. An updated copy of the input
 * image is saved here.
 *
 * @param string image description.
 *
 * @param string user comment.
 *
 * @param string camera model.
 *
 * @param float longitude expressed as a fractional number of degrees,
 * e.g. 12.345 Negative values denotes degrees west of Greenwich.
 *
 * @param float latitude expressed as for longitude. Negative values
 * denote degrees south of equator.
 *
 * @param float the altitude, negative values express an altitude
 * below sea level.
 *
 * @param string the date and time.
 */

function addGpsInfo($input, $output, $description, $comment, $model,
		$longitude, $latitude, $altitude, $date_time) {
  /* Load the given image into a PelJpeg object */
	$jpeg = new PelJpeg($input);

	/* Create and add empty Exif data to the image (this throws away any
	* old Exif data in the image). */
	$exif = new PelExif();
	$jpeg->setExif($exif);

	/* Create and add TIFF data to the Exif data (Exif data is actually
	* stored in a TIFF format). */
	$tiff = new PelTiff();
	$exif->setTiff($tiff);

	/* Create first Image File Directory and associate it with the TIFF
	* data. */
	$ifd0 = new PelIfd(PelIfd::IFD0);
	$tiff->setIfd($ifd0);

	/* Create a sub-IFD for holding GPS information. GPS data must be
	* below the first IFD. */
	$gps_ifd = new PelIfd(PelIfd::GPS);
	$ifd0->addSubIfd($gps_ifd);

	/* The USER_COMMENT tag must be put in a Exif sub-IFD under the
	* first IFD. */
	$exif_ifd = new PelIfd(PelIfd::EXIF);
	$exif_ifd->addEntry(new PelEntryUserComment($comment));
	$ifd0->addSubIfd($exif_ifd);

	$inter_ifd = new PelIfd(PelIfd::INTEROPERABILITY);
	$ifd0->addSubIfd($inter_ifd);

	$ifd0->addEntry(new PelEntryAscii(PelTag::MODEL, $model));
	$ifd0->addEntry(new PelEntryAscii(PelTag::DATE_TIME, $date_time));
	$ifd0->addEntry(new PelEntryAscii(PelTag::IMAGE_DESCRIPTION, $description));

	$gps_ifd->addEntry(new PelEntryByte(PelTag::GPS_VERSION_ID, 2, 2, 0, 0));

	/* Use the convertDecimalToDMS function to convert the latitude from
	* something like 12.34� to 12� 20' 42" */
	list($hours, $minutes, $seconds) = convertDecimalToDMS($latitude);

	/* We interpret a negative latitude as being south. */
	$latitude_ref = ($latitude < 0) ? 'S' : 'N';

	$gps_ifd->addEntry(new PelEntryAscii(PelTag::GPS_LATITUDE_REF,
				$latitude_ref));
	$gps_ifd->addEntry(new PelEntryRational(PelTag::GPS_LATITUDE,    
				$hours, $minutes, $seconds));

	/* The longitude works like the latitude. */
	list($hours, $minutes, $seconds) = convertDecimalToDMS($longitude); 
	$longitude_ref = ($longitude < 0) ? 'W' : 'E';

	$gps_ifd->addEntry(new PelEntryAscii(PelTag::GPS_LONGITUDE_REF,
				$longitude_ref));
	$gps_ifd->addEntry(new PelEntryRational(PelTag::GPS_LONGITUDE,
				$hours, $minutes, $seconds));

	/* Add the altitude. The absolute value is stored here, the sign is
	* stored in the GPS_ALTITUDE_REF tag below. */
	$gps_ifd->addEntry(new PelEntryRational(PelTag::GPS_ALTITUDE,
				array(abs($altitude), 1)));
	/* The reference is set to 1 (true) if the altitude is below sea
	* level, or 0 (false) otherwise. */
	$gps_ifd->addEntry(new PelEntryByte(PelTag::GPS_ALTITUDE_REF,
				(int)($altitude < 0)));

	/* Finally we store the data in the output file. */
	file_put_contents($output, $jpeg->getBytes());
}

//from http://php.net/manual/en/function.checkdate.php#78362
function isValidDateTime($dateTime)
{
	if (preg_match("/^(\d{4})-(\d{2})-(\d{2}) ([01][0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9])$/", $dateTime, $matches)) {
		if (checkdate($matches[2], $matches[3], $matches[1])) {
			return true;
		}
		return false;
	}

	return false;
}

function geocodeByAddress($address){
	/*
		 * Code borrowed from http://www.timshowers.com/2008/08/php-geocoding-tutorial-with-the-google-maps-api-part-one

	 */
	//Three parts to the querystring: q is address, output is the format (
	//$key = "YOUR KEY HERE";
	$address = urlencode($address);
	$url = "http://maps.google.com/maps/geo?q=".$address."&output=csv";

	$ch = curl_init();

	curl_setopt($ch, CURLOPT_URL, $url);
	curl_setopt($ch, CURLOPT_HEADER,0);
	curl_setopt($ch, CURLOPT_USERAGENT, $_SERVER["HTTP_USER_AGENT"]);
	curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
	curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);

	$data = curl_exec($ch);
	curl_close($ch);

	//Check our Response code to ensure success
	if (substr($data,0,3) == "200")
	{
		$data = explode(",",$data);

		$precision = $data[1];
		$latitude = $data[2];
		$longitude = $data[3];

		$rtn = array();
		$rtn['latitude'] = $latitude;
		$rtn['longitude'] = $longitude;
		$rtn['precision'] = $precision;

		return $rtn;
	} 
	else {
		//echo "Error in geocoding! Http error ".substr($data,0,3);
		return FALSE;
	}
}


$errorlog = $BASE_DIR.'/../logs/post_image.log';

file_put_contents($errorlog,'-----'.PHP_EOL.print_r($_REQUEST, true).PHP_EOL, FILE_APPEND);
file_put_contents($errorlog,print_r($_FILES, true).PHP_EOL, FILE_APPEND);
// check if file uploaded
if (isset($_FILES['file']) && $_FILES['file']['tmp_name'] != '') {
	$file_name = $_FILES['file']['name'];
	$file_temp_name = $_FILES['file']['tmp_name'];
	$file_type = $_FILES['file']['type'];
	$file_size = $_FILES['file']['size'];
}
else {
	header('HTTP/1.1 400 Bad Request');
	file_put_contents($errorlog,"No file uploaded.".PHP_EOL, FILE_APPEND);
	die('No File Uploaded.');
}

// check for username
if (isset($_REQUEST['username']) && $_REQUEST['username'] != '') {
	$username = $_REQUEST['username'];
	file_put_contents($errorlog,"username: $username".PHP_EOL, FILE_APPEND);
}
else {
	header('HTTP/1.1 400 Bad Request');
	file_put_contents($errorlog,"Missing username.".PHP_EOL, FILE_APPEND);
	die('Missing required field: username');
}

// check for password
if (isset($_REQUEST['password']) && $_REQUEST['password'] != '') {
	$password = md5($_REQUEST['password']);
	file_put_contents($errorlog,"password set".PHP_EOL, FILE_APPEND);
}
else {
	header('HTTP/1.1 400 Bad Request');
	file_put_contents($errorlog,"Missing password.".PHP_EOL, FILE_APPEND);
	die('Missing required field: password');
}

// open database
$db = new PDO("sqlite:".$DATABASE);

$query = "SELECT username, usergroup FROM user WHERE username = :user AND password = :pass";
$select = $db->prepare($query);
if (!$select)  {
	header('HTTP/1.1 500 Internal Server Error');
	file_put_contents($errorlog,"Error preparing db statement.".PHP_EOL, FILE_APPEND);
	die('there is a problem with the database');
}
else {
	$select->execute(array(':user'=>$username, ':pass'=>$password));
	$row = $select->fetch(PDO::FETCH_ASSOC);
	if (!$row || count($row) < 2) {
		header('HTTP/1.1 401 Unauthorized');
		file_put_contents($errorlog,"User not authenticated. row false or < 2".PHP_EOL, FILE_APPEND);
		die('User could not be authenticated.');
	}
	// redundant check...
	else if ($row['username'] != $username) {
		header('HTTP/1.1 401 Unauthorized');
		file_put_contents($errorlog,"User not match".PHP_EOL, FILE_APPEND);
		die('User could not be authenticated.');
	}
	else {
		$username = $row['username'];
		$groupname = $row['usergroup'];
	}

}
$db = null;


// check for datetime
if (isset($_REQUEST['datetime']) && $_REQUEST['datetime'] != '') {
	$dtmp = $_REQUEST['datetime'];

	// check datetime format
/*	if (!isValidDateTime($dt)) {
		header('HTTP/1.1 400 Bad Request');
		file_put_contents($errorlog,"Bad format date".PHP_EOL, FILE_APPEND);
		die('Incorrect format: datetime');
	}
*/
	date_default_timezone_set('PDT');

        $utime = strtotime($dtmp);
	if (!$utime) {
		header('HTTP/1.1 400 Bad Request');
		file_put_contents($errorlog,"Bad format date".PHP_EOL, FILE_APPEND);
		die('Incorrect format: datetime');
	}

        $dt = date('Y-m-d H:i:s', $utime);


	$temp = explode(" ", $dt);
	$d = $temp[0];
	$t = $temp[1];
	$title = $d;
	file_put_contents($errorlog,"$d,$t set".PHP_EOL, FILE_APPEND);
}
else {
	header('HTTP/1.1 400 Bad Request');
	file_put_contents($errorlog,"Missing datetime date".PHP_EOL, FILE_APPEND);
	die('Missing required field: datetime');
}

// check for tag
if (isset($_REQUEST['tag']) && $_REQUEST['tag'] != '') {
	$tag = $_REQUEST['tag'];
	$flickrtaglist = $tag;
	file_put_contents($errorlog,"tag: $tag".PHP_EOL, FILE_APPEND);
}
else {
	$tag = 'notag';
	$flickrtaglist = $tag;
//	header('HTTP/1.1 400 Bad Request');
//	file_put_contents($errorlog,"missing tag".PHP_EOL, FILE_APPEND);
//	die('Missing required field: tag');
}

// check for optional location data
if (isset($_REQUEST['latitude']) && isset($_REQUEST['longitude']) && $_REQUEST['latitude'] != '' && $_REQUEST['longitude'] != '') {
	$latitude = $_REQUEST['latitude'];
	$longitude = $_REQUEST['longitude'];
	file_put_contents($errorlog,"location: $latitude,$longitude".PHP_EOL, FILE_APPEND);
}
else if (isset($_REQUEST['geotag']) && $_REQUEST['geotag'] != '') {
	$geotag = $_REQUEST['geotag'];
	file_put_contents($errorlog,"geotag: $geotag".PHP_EOL, FILE_APPEND);
	$flickrtaglist .= ",".$geotag;
	$loc = geocodeByAddress($geotag);
	if ($loc != false) {
		$latitude = $loc['latitude'];
		$longitude = $loc['longitude'];
	}
}
/*else {
	header('HTTP/1.1 400 Bad Request');
	die('Missing required field: latitude+longitude or geotag');
}//*/



// check file size < 5mb
if ($file_size > 5242880) {
	header('HTTP/1.1 413 Request Entity Too Large');
	file_put_contents($errorlog,"file too large.".PHP_EOL, FILE_APPEND);
	die('The File uploaded is too large');
}

// check file type
if(($file_type == "image/png") || ($file_type == "image/gif") || ($file_type == "image/jpeg") || ($file_type == "application/octet-stream")){
	// setup flickr
	require_once($INCLUDE_DIR.'phpflickr.helper.php');
	$f->auth('write');

	$tag = strtolower($tag);
	$username = strtolower($username);
	$groupname = strtolower($groupname);
	$flickrtaglist = strtolower($flickrtaglist);

	$flickrtaglist = str_replace(" ", "_", $flickrtaglist);

	// if location data set, upload geotagged image
	$file_name = '/tmp/'.$file_name;

	if (isset($longitude) && $longitude != '' && isset($latitude) && $latitude != '' && ($longitude!='0' && $latitude!='0')) {
		file_put_contents($errorlog,"Attempt tag image.".PHP_EOL, FILE_APPEND);
		addGpsInfo($file_temp_name, $file_name, "", "", "", $longitude, $latitude, "", $dt);

		$response = $f->sync_upload($file_name, $title, "", $flickrtaglist, 1, 1, 1);
		Cametrics::measure($username.".contributions.location.all", $longitude.",".$latitude, 'location');
		Cametrics::measure($groupname.".contributions.location.all", $longitude.",".$latitude, 'location');
		Cametrics::measure("contributions.location.all", $longitude.",".$latitude, 'location');

		Cametrics::measure($username.".contributions.location.".$tag, $longitude.",".$latitude, 'location');
		Cametrics::measure($groupname.".contributions.location.".$tag, $longitude.",".$latitude, 'location');
		Cametrics::measure("contributions.location.".$tag, $longitude.",".$latitude, 'location');

		Cametrics::measure("$groupname.contributions.location.$username.$tag", $longitude.",".$latitude, 'location');
		Cametrics::measure("contributions.location.$username.$tag", $longitude.",".$latitude, 'location');

		Cametrics::measure("$groupname.contributions.location.$username.all", $longitude.",".$latitude, 'location');
		Cametrics::measure("contributions.location.$username.all", $longitude.",".$latitude, 'location');

		file_put_contents($errorlog, 
			$dt.': "'.$flickrtaglist.'" ('.$latitude.' '.$longitude.')'.PHP_EOL.'-- '.$response.PHP_EOL, 
			FILE_APPEND);
	}
	// if no location data, just upload image to flickr
	else
	{
		file_put_contents($errorlog,"Attempt upload untagged image.".PHP_EOL, FILE_APPEND);
		if (!move_uploaded_file($file_temp_name, $file_name)) { 
			header('HTTP/1.1 400 Bad Request');
			file_put_contents($errorlog,"File could not be moved".PHP_EOL, FILE_APPEND);
			die('File could not be moved.');
		}
		$response = $f->sync_upload($file_name, $title, "", $flickrtaglist, 1, 1, 1);
		file_put_contents($errorlog, 
			$dt.': "'.$flickrtaglist.'" (no location) '.PHP_EOL.'-- '.$response.PHP_EOL, 
			FILE_APPEND);
	}

	Cametrics::measure($username.".contributions.type", $tag, 'string');
	Cametrics::measure($username.".contributions.time", $dt, 'datetime');

	Cametrics::measure($groupname.".contributions", $username, 'string');   
	Cametrics::measure($groupname.".contributions.type", $tag, 'string');
	Cametrics::measure($groupname.".contributions.time", $dt, 'datetime');
	Cametrics::measure("contributions.group", $groupname, 'string');


	Cametrics::measure("contributions", $username, 'string');
	Cametrics::measure("contributions.type", $tag, 'string');
	Cametrics::measure("contributions.time", $dt, 'datetime');

}
else
{
	header('HTTP/1.1 415 Unsupported Media Type');
	die('Uploaded file type must be: png, gif, jpeg, or octet-stream');
}

?>
